package p.ithorns.framework.common.reflect;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * UnsafeUtil
 *
 * @author Ht.L
 * @date 2024-05-03 15:59
 * @since 1.0.0
 */
@SuppressWarnings("restriction")
public class UnsafeUtil {

    // private final static Logger log = LoggerFactory.getLogger(UnsafeUtil.class);

    /**
     * Unsafe mechanics
     */
    private static final sun.misc.Unsafe UNSAFE;

    static {
        try {
            UNSAFE = reflectGetUnsafe();
            assert UNSAFE != null;
        } catch (Exception e) {
            throw new Error(e);
        }
    }

    private static Unsafe reflectGetUnsafe() {
        try {
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            return (Unsafe) field.get(null);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    public static void replaceModule(Class<?> clazz) {
        try {
            Module module = Object.class.getModule();
            long addr = UNSAFE.objectFieldOffset(Class.class.getDeclaredField("module"));
            UNSAFE.getAndSetObject(clazz, addr, module);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
    }

    public static void putOrderedInt(Object obj, long stateOffset, int exceptional) {
        UNSAFE.putOrderedInt(obj, stateOffset, exceptional);
    }


    // 实现compareAndSwapInt方法
    public static boolean compareAndSwap(Object obj, long offset, int expect, int update) {
        return UNSAFE.compareAndSwapInt(obj, offset, expect, update);
    }

    public static boolean compareAndSwapObject(Object o, long offset,
                                               Object expected,
                                               Object x) {
        return UNSAFE.compareAndSwapObject(o, offset, expected, x);
    }

    public static long objectFieldOffset(Class<?> clazz, String filedName) {
        try {
            Field declaredField = clazz.getDeclaredField(filedName);
            return UNSAFE.objectFieldOffset(declaredField);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
    }

    public static List<Field> getAllFieldsList(final Class<?> cls) {
        assert null != cls;
        final List<Field> allFields = new ArrayList<>();
        Class<?> currentClass = cls;
        while (currentClass != null) {
            final Field[] declaredFields = currentClass.getDeclaredFields();
            Collections.addAll(allFields, declaredFields);
            currentClass = currentClass.getSuperclass();
        }
        return allFields;
    }

}